#include <regx52.h>
#include "uart.c"
sbit N_R = P2 ^ 0;
sbit N_G = P2 ^ 1;
sbit N_Y = P2 ^ 2;
sbit E_R = P2 ^ 3;
sbit E_G = P2 ^ 4;
sbit E_Y = P2 ^ 5;

#define LEDS P2

sbit BTN_EMERGENCY = P1 ^ 0;
sbit BTN_NIGHT = P1 ^ 1;
sbit BTN_PEOPLE = P1 ^ 2;

sbit LED_PEOPLE = P1 ^ 3;

#define PRESSED_EMERGENCY 0
#define PRESSED_NIGHT 1
#define PRESSED_PEOPLE 2
#define PRESSED_NONE 0xFF

unsigned char btn_scan()
{
    if (BTN_EMERGENCY == 0)
    {
        while (BTN_EMERGENCY == 0)
        {
        }
        return PRESSED_EMERGENCY;
    }

    if (BTN_NIGHT == 0)
    {
        while (BTN_NIGHT == 0)
        {
        }
        return PRESSED_NIGHT;
    }
    if (BTN_PEOPLE == 0)
    {
        while (BTN_PEOPLE == 0)
        {
        }
        return PRESSED_PEOPLE;
    }
    return PRESSED_NONE;
}

void delay_ms(unsigned int ms)
{
    unsigned int i, j;
    for (i = 0; i < ms; i++)
    {
        for (j = 0; j < 123; j++)
            ;
    }
}

typedef enum
{
    EMERGENCY,  // 紧急模式，所有红灯闪烁
    NIGHT,      // 夜晚模式，所有黄灯闪烁
    NORMAL_N_G, // 南北方向绿灯
    NORMAL_N_Y, // 南北方向黄灯闪烁
    NORMAL_E_G, // 东西方向绿灯
    NORMAL_E_Y, // 东西方向绿灯闪烁

} StateEnum;

StateEnum state = NORMAL_N_G;

#define MONITOR_STEP_MS 100
#define LED_FLASHING_DELAY 500
#define LED_CHANGE_DELAY 5000
#define PEDESTRIAN_TIME 5000

unsigned int green_light_extension_time = 0;

/**
 * 延迟的过程中进行按键扫描，对状态进行修改
 * @return 1:状态修改，延时没有完全结束 0:延时完全结束
 */
bit monitor_btn_state(unsigned int total_delay)
{
    unsigned int i;
    unsigned char btn;
    // 每隔 MONITOR_STEP_MS 检测按键的变化
    for (i = 0; i < total_delay; i += MONITOR_STEP_MS)
    {
        // 每次扫描一旦变化，延时就增加到总延时上
        if (green_light_extension_time > 0)
        {
            if (state == NORMAL_E_G || state == NORMAL_N_G)
            {
                total_delay += green_light_extension_time;
                green_light_extension_time = 0;
            }
        }

        // 延时
        delay_ms(MONITOR_STEP_MS);

        // 按键检测
        btn = btn_scan();
        // 根据按下的具体按键，切换状态
        switch (btn)
        {
        case PRESSED_EMERGENCY:
            if (state == EMERGENCY)
            {
                state = NORMAL_E_G;
            }
            else
            {
                state = EMERGENCY;
            }
            green_light_extension_time = 0;
            LED_PEOPLE = 1;
            return 1;
        case PRESSED_NIGHT:
            if (state == NIGHT)
            {
                state = NORMAL_E_G;
            }
            else
            {
                state = NIGHT;
            }
            green_light_extension_time = 0;
            LED_PEOPLE = 1;
            return 1;
        case PRESSED_PEOPLE:
            if (state != EMERGENCY && state != NIGHT)
            {
                green_light_extension_time = PEDESTRIAN_TIME;
                LED_PEOPLE = 0;
            }
            break;
        default:
            break;
        }
    }
    return 0;
}

void process_emergency()
{
    LEDS = 0xFF;
    while (state == EMERGENCY)
    {
        E_R = 0;
        N_R = 0;
        if (monitor_btn_state(LED_FLASHING_DELAY))
        {
            LEDS = 0xFF;
            return;
        }
        E_R = 1;
        N_R = 1;
        if (monitor_btn_state(LED_FLASHING_DELAY))
        {
            LEDS = 0xFF;
            return;
        }
    }
}

void process_night()
{
    LEDS = 0xFF;
    while (state == NIGHT)
    {
        E_Y = 0;
        N_Y = 0;
        if (monitor_btn_state(LED_FLASHING_DELAY))
        {
            LEDS = 0xFF;
            return;
        }
        E_Y = 1;
        N_Y = 1;
        if (monitor_btn_state(LED_FLASHING_DELAY))
        {
            LEDS = 0xFF;
            return;
        }
    }
}

void normal_n_y()
{
    unsigned char i;
    N_G = 1;
    for (i = 0; i < 3; i++)
    {
        N_Y = 0;
        if (monitor_btn_state(LED_FLASHING_DELAY))
        {
            return;
        }
        N_Y = 1;
        if (monitor_btn_state(LED_FLASHING_DELAY))
        {
            return;
        }
    }
    state = NORMAL_E_G;
}

void normal_e_y()
{
    unsigned char i;
    E_G = 1;
    for (i = 0; i < 3; i++)
    {
        E_Y = 0;
        if (monitor_btn_state(LED_FLASHING_DELAY))
        {
            return;
        }
        E_Y = 1;
        if (monitor_btn_state(LED_FLASHING_DELAY))
        {
            return;
        }
    }
    state = NORMAL_N_G;
}

void main(void)
{
    unsigned char i;
    P2 = 0xFF;
    uart_init();
    while (1)
    {
        switch (state)
        {
        case EMERGENCY:
            process_emergency();
            break;
        case NIGHT:
            process_night();
            break;
        case NORMAL_N_G:
            // 阶段1：南北方向绿灯，东西方向红灯，持续5秒
            N_R = 1;
            N_G = 0;
            E_R = 0;
            if (!monitor_btn_state(LED_CHANGE_DELAY))
            {
                state = NORMAL_N_Y;
                LED_PEOPLE = 1;
            }
            break;
        case NORMAL_N_Y:
            // 阶段2：南北方向其他灯灭，
            // 黄灯闪烁3次（500ms），东西方向红灯保持
            normal_n_y();
            break;
        case NORMAL_E_G:
            // 阶段3：东西方向绿灯，南北方向红灯，持续5秒
            E_R = 1;
            E_G = 0;
            N_R = 0;
            if (!monitor_btn_state(LED_CHANGE_DELAY))
            {
                state = NORMAL_E_Y;
                LED_PEOPLE = 1;
            }
            break;
        case NORMAL_E_Y:
            // 阶段4：东西方向其他灯灭，黄灯闪烁3次（500ms），南北方向红灯保持
            normal_e_y();
            break;
        default:
            break;
        }
    }
}